using System;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace Trentacular.SharePoint.SmartEditorPart.Web.UI.WebParts
{
    /// <summary>
    /// Web Part that lists members of the Site Collection and allows
    /// for configuring which fields should be displayed.
    /// </summary>
    [Guid("ee9006de-db22-479e-b723-eec6eb3fa103")]
    [EditorPart("SiteMemberFieldsEditor", "Fields to Display",
        "~/_controltemplates/trentacular/smarteditorpart/SiteMemberFieldsEditor.ascx")]
    public class SiteMembersWebPart : WebEditableWebPart
    {
        #region Persistent Properties

        private SiteMemberFieldCollection _fields;

        /// <summary>
        /// Gets or sets the user fields to display.
        /// </summary>
        /// <value>The fields to be displayed.</value>
        [Personalizable(PersonalizationScope.Shared)]
        public SiteMemberFieldCollection Fields
        {
            get
            {
                if (_fields == null)
                    _fields = GetDefaultFieldsConfiguration();
                return _fields;
            }
            set
            {
                _fields = value;
            }
        }

        #endregion

        private const string USER_ID_COLUMN_NAME = "UserID";

        private SPGridView gvSiteMembers;

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use
        /// composition-based implementation to create any child controls they contain
        /// in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls()
        {
            gvSiteMembers = new SPGridView
            {
                EnableViewState = false,
                AutoGenerateColumns = false
            };
            this.Controls.Add(gvSiteMembers);

            base.CreateChildControls();
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that
        /// contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            var spContext = SPContext.Current;
            var web = spContext.Web;
            var siteInfoUserList = web.SiteUserInfoList;

            var dataTable = new DataTable();

            var dataNavigateUrlFormatString = string.Format(
                "{0}/_layouts/userdisp.aspx?ID={{0}}",
                web.Url.TrimEnd('/')
                );

            var dataNavigateUrlFields = new[] { USER_ID_COLUMN_NAME };

            foreach (var field in this.Fields)
            {
                if (!siteInfoUserList.Fields.ContainsField(field.FieldName))
                    continue;

                // Create the GridView column
                gvSiteMembers.Columns.Add(new HyperLinkField
                {
                    HeaderText = field.DisplayName,
                    DataTextField = field.FieldName,
                    DataNavigateUrlFormatString = dataNavigateUrlFormatString,
                    DataNavigateUrlFields = dataNavigateUrlFields
                });

                // Create the DataTable column
                dataTable.Columns.Add(field.FieldName);
            }

            var fieldNames = dataTable.Columns.Cast<DataColumn>()
                .Select(c => c.ColumnName)
                .ToArray();

            var allItems = siteInfoUserList.GetItems(fieldNames);
            var siteUserIDs = web.SiteUsers.Cast<SPUser>()
                .Select(u => u.ID)
                .ToList();

            // Add additional column to store the UserID for hyperlinks
            dataTable.Columns.Add(USER_ID_COLUMN_NAME);

            foreach (SPListItem item in allItems)
            {
                // If not a user, move to next record
                if (!siteUserIDs.Contains(item.ID))
                    continue;

                var row = dataTable.NewRow();
                foreach (var fieldName in fieldNames)
                {
                    row[fieldName] = item[fieldName];
                }

                row[USER_ID_COLUMN_NAME] = item.ID;
                dataTable.Rows.Add(row);
            }

            gvSiteMembers.DataSource = dataTable;
            gvSiteMembers.DataBind();

            base.OnPreRender(e);
        }

        private SiteMemberFieldCollection GetDefaultFieldsConfiguration()
        {
            return new SiteMemberFieldCollection
            {
                new SiteMemberField { DisplayName = "Name", FieldName = "Title" },
                new SiteMemberField { DisplayName = "Email", FieldName = "EMail" },
                new SiteMemberField { DisplayName = "Login Name", FieldName = "Name" }
            };
        }
    }
}
